package pe.edu.upla.lamerced.DAO.impl;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;

import org.hibernate.Criteria;
import org.hibernate.Query;
import org.hibernate.SQLQuery;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.criterion.Restrictions;
import org.springframework.orm.hibernate3.HibernateTemplate;
import org.springframework.orm.hibernate3.support.HibernateDaoSupport;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import pe.edu.upla.lamerced.DAO.HospedajeDAO;
import pe.edu.upla.lamerced.Utiles;
import pe.edu.upla.lamerced.bean.Categoria;
import pe.edu.upla.lamerced.bean.Detallefactura;
import pe.edu.upla.lamerced.bean.Factura;
import pe.edu.upla.lamerced.bean.Habitacion;
import pe.edu.upla.lamerced.bean.Hospedaje;
import pe.edu.upla.lamerced.bean.Tipohabitacion;

/**
 * estado 0 = reserva finalizada<br/>
 * estado 1 = reservado <br/>
 * estado 2 = hospedaje<br/>
 * estado 3 = hospedaje finalizado<br/>
 * 
 * @author elvis
 *
 */


public class HospedajeDAOImpl extends HibernateDaoSupport implements HospedajeDAO {

	public HospedajeDAOImpl(){}
	
	
	public HospedajeDAOImpl(SessionFactory sessionFactory){
		setHibernateTemplate( new HibernateTemplate(sessionFactory));
	}
	
	@Override
	@Transactional(propagation=Propagation.REQUIRES_NEW)
	public void registrarHospedaje(Hospedaje hospedaje) {
		this.getHibernateTemplate().merge(hospedaje);
		this.getHibernateTemplate().merge(hospedaje.getHabitacion());
	}

	@Override
	@Transactional(propagation=Propagation.REQUIRES_NEW)
	public void registrarHospedajeReserva(Hospedaje hospedaje) {
		this.getHibernateTemplate().persist(hospedaje);
	}


	@Override
	@Transactional(propagation=Propagation.MANDATORY)
	public void registrarReserva(Hospedaje hospedaje) {
		this.getHibernateTemplate().persist(hospedaje);
	}

	@Override
    @Transactional(readOnly=true)
	public Hospedaje obtenerReserva(Integer idhospedaje) {
       //ha.estado=1 and ya no me importa el stado
		Query query = getSession().createQuery("select h from Hospedaje h inner join h.habitacion ha where h.estado = 1 and  idhospedaje = :id  ")
        .setInteger("id", idhospedaje);
        Hospedaje h = (Hospedaje)query.uniqueResult();        
		return h;
	}

	@Override
    @Transactional(readOnly=true)
	public Hospedaje obtenerHospedaje(Integer idhospedaje) {
      Session session = null;
      try {
          session = getSession();
          Query query = session.createQuery("select h from Hospedaje h where h.idhospedaje = :id  ")
          .setInteger("id", idhospedaje);
          Hospedaje h = (Hospedaje)query.uniqueResult();
          return h;
      }finally {
          releaseSession(session);
      }
    }

	
	@SuppressWarnings("unchecked")
    @Transactional(readOnly=true)
	@Override
	public List<Hospedaje> listarRserva(Hospedaje hospedaje) {	
		Criteria crit = getSession().createCriteria(Hospedaje.class);
		if(hospedaje.getEstado()==null){
			crit.add(Restrictions.eq("estado",1));
		}else{
			crit.add(Restrictions.eq("estado",hospedaje.getEstado()));
		}  
		System.out.println("ya puse el estado");
       if(hospedaje.getUsersByIdUsuarioCli()!=null){
           Criteria crit2 = crit.createCriteria("usersByIdUsuarioCli");
           crit2.add(Restrictions.eq("username",hospedaje.getUsersByIdUsuarioCli().getUsername()));
           System.out.println("ya puse el cliente");
       }

       if(hospedaje.getHabitacion()!=null){
          System.out.println("ya puse la habitacion");
           if(hospedaje.getHabitacion().getEstado()!=null){
               Criteria crit2 = crit.createCriteria("habitacion");
               crit2.add(Restrictions.eq("estado",hospedaje.getHabitacion().getEstado()));
           }
           if(hospedaje.getHabitacion().getTipohabitacion()!=null){
               Criteria crit2 = crit.createCriteria("habitacion");
               crit2.add(Restrictions.eq("tipohabitacion.idtipoHabitacion",hospedaje.getHabitacion().getTipohabitacion().getIdtipoHabitacion()));
           }
       }
		return crit.list();
	}

	@Override
	@Transactional(propagation=Propagation.MANDATORY)
	public void finalizarreserva(Hospedaje hospedaje) {		
		this.getHibernateTemplate().saveOrUpdate(hospedaje);
	}

	@SuppressWarnings("unchecked")
    @Transactional(readOnly=true)
	@Override
	public List<Hospedaje> listaHospedajes(String usuario) {
		if(!usuario.equals("")){
			Query query = getSession().createQuery(" from Hospedaje h where estado in ('2','3')  and usersByIdUsuarioCli.username = :usuario  ")
	        .setString("usuario", usuario);
			return query.list();
		}
		return this.getHibernateTemplate().find("from Hospedaje h where estado in ('2','3') ");
	}

	@SuppressWarnings("unchecked")
    @Transactional(readOnly=true)
	@Override
	public List<Habitacion> buscarHabitacionesdisponibles(Hospedaje hospedaje) {
		//TODO: pendiente query que me diga las habitaciones que no tienen reserva
		//el dia que se indica
		//return this.getHibernateTemplate()
		//.find("select h from Habitacion h  ");

            	//TODO: pendiente query que me diga las habitaciones que no tienen reserva
		//el dia que se indica
		boolean where = false;
		StringBuilder sql = new StringBuilder();
		try {
		sql.append(" select idhabitacion, h.idtipohabitacion,thab.nombre as ntah ,h.idcategoria, cat.nombre as ncat, ");
		sql.append(" numero,piso,estado,preciobase ");
		sql.append(" from habitacion h ");
		sql.append(" inner join categoria cat on h.idcategoria=cat.idcategoria ");
		sql.append(" inner join tipohabitacion thab on h.idtipohabitacion=thab.idtipohabitacion ");
		sql.append("where  ");
		if(!Utiles.nullToBlank( hospedaje.getHabitacion().getTipohabitacion().getIdtipoHabitacion() ).equals("")){
			logger.debug("tipo de habitacion " + hospedaje.getHabitacion().getTipohabitacion().getIdtipoHabitacion());
			sql.append(" h.idtipoHabitacion = "  ).append( hospedaje.getHabitacion().getTipohabitacion().getIdtipoHabitacion());
			where = true;
		}
		if(!Utiles.nullToBlank( hospedaje.getHabitacion().getCategoria().getIdcategoria() ).equals("")){
			logger.debug(" categoria " + hospedaje.getHabitacion().getCategoria().getIdcategoria() );
			if(where){ sql.append(" and ");}
			sql.append(" h.idcategoria = " ).append( hospedaje.getHabitacion().getCategoria().getIdcategoria());
			where = true;
		}
		if(where){ sql.append(" and ");}
		sql.append(" h.idhabitacion not in (");
		sql.append(" select hab.idhabitacion from hospedaje hos ");
		sql.append(" inner join habitacion hab on hab.idhabitacion=hos.idhabitacion ");
		sql.append(" where ");

			sql.append(" fecreserva = '"  ).append( Utiles.dateToString(hospedaje.getFecReserva(), Utiles.FORMATO_FECHA_CORTA_MYSQL)  ).append( "' and estado=1 ");

		if(!Utiles.nullToBlank( hospedaje.getHabitacion().getTipohabitacion().getIdtipoHabitacion() ).equals("")){
			sql.append(" and hab.idtipoHabitacion = " ).append(hospedaje.getHabitacion().getTipohabitacion().getIdtipoHabitacion());
		}
		if(!Utiles.nullToBlank( hospedaje.getHabitacion().getCategoria().getIdcategoria() ).equals("")){
			sql.append(" and hab.idcategoria = " ).append( hospedaje.getHabitacion().getCategoria().getIdcategoria());
		}
		sql.append("  )");
		} catch (Exception e) {
			e.printStackTrace();
		}

		logger.debug(" buscarHabitacionesdisponibles - pendiente por compeltar");
		logger.debug(sql.toString()	);
		SQLQuery query = getSession().createSQLQuery(sql.toString());
		List lista = query.list();
		List<Habitacion> resultado = new ArrayList<Habitacion>();
		Habitacion hab = null;
		if(lista!=null){
			for(Object o : lista){
				hab = new Habitacion();
				Object[] oj = (Object[]) o;
				hab.setIdhabitacion((Integer)oj[0]);
				Tipohabitacion thab = new Tipohabitacion();
				thab.setIdtipoHabitacion((Integer)oj[1]);
				thab.setNombre((String)oj[2]);
				hab.setTipohabitacion(thab);
				Categoria cat = new Categoria();
				cat.setIdcategoria((Integer)oj[3]);
				cat.setNombre((String)oj[4]);
				hab.setCategoria(cat);
				hab.setNumero((Integer)oj[5]);
				hab.setPiso((Integer)oj[6]);
				hab.setEstado((Integer)oj[7]);
				hab.setPrecioBase((BigDecimal)oj[8]);
				resultado.add(hab);
			}
		}
		return resultado; 
	}

	@Override
    @Transactional(propagation=Propagation.REQUIRED)
	public void anularReserva(int codigo) {
		Hospedaje h = obtenerReserva(codigo);
        if(h==null){System.out.println("No existe la reserva");return;}
		h.setEstado(0);
		h.getHabitacion().setEstado(0);
		
		this.getHibernateTemplate().merge(h);
		this.getHibernateTemplate().merge(h.getHabitacion());
	}

	@SuppressWarnings("unchecked")
	@Override
    @Transactional(readOnly=true)
	public List<Hospedaje> listaHospedajesActivos() {
		return this.getHibernateTemplate().find("select h from Hospedaje h where estado = 2");
	}

	@Override
	@Transactional(propagation=Propagation.MANDATORY)
	public void registrarFactura(Factura fac, List<Detallefactura> lisDet) {
		this.getHibernateTemplate().persist(fac);
		this.getHibernateTemplate().merge(fac.getHospedaje());
		this.getHibernateTemplate().merge(fac.getHospedaje().getHabitacion());
		for(Detallefactura det : lisDet){
			this.getHibernateTemplate().persist(det);	
		}
	}

   @Transactional(readOnly=true)
   public Hospedaje obtenerReservaExacta(String fecha,String habitacion) {
     try {
         Query query = getSession().createQuery("select h from Hospedaje h where h.fecReserva = :fecha and h.habitacion.idhabitacion= :hab")
         .setInteger("hab", Integer.parseInt(habitacion))
         .setDate("fecha", Utiles.stringToDate(fecha,"dd/MM/yyyy"));
         return (Hospedaje)query.uniqueResult();
      } catch (Exception e) {
         e.printStackTrace();
         return null;
      }
   }

    @Transactional(readOnly=true)
    public Hospedaje obtenerHospedajeExacto(String fecha,String habitacion) {
      try {
         Query query = getSession().createQuery("select h from Hospedaje h where h.fecAlquiler = :fecha and h.habitacion.idhabitacion= :hab ")
         .setInteger("hab", Integer.parseInt(habitacion))
         .setDate("fecha", Utiles.stringToDate(fecha,"dd/MM/yyyy"));
         return (Hospedaje)query.uniqueResult();
      } catch (Exception e) {
          e.printStackTrace();
         return null;
      }
     
   }

   public void anularHospedaje(int cod) {
        Hospedaje h = obtenerHospedaje(cod);
		h.setEstado(3);
		h.getHabitacion().setEstado(0);
        this.getHibernateTemplate().merge(h);
		this.getHibernateTemplate().merge(h.getHabitacion());
   }
	
}
